package com.moli.iov.util;

import org.apache.log4j.Logger;
import org.springframework.core.io.ClassPathResource;

import javax.activation.DataHandler;
import javax.mail.*;
import javax.mail.internet.*;
import javax.mail.util.ByteArrayDataSource;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

public class MailUtil {
    private static Logger logger = Logger.getLogger(MailUtil.class);

    static {

        PropertiesUtils.getProperty("config.properties");
        email_account = PropertiesUtils.getProperty("email_account");
        email_password = PropertiesUtils.getProperty("email_password");
    }

    private static String email_account;
    private static String email_password;
    private static final String ALIDM_SMTP_HOST = "smtp.mxhichina.com";
    private static final String ALIDM_SMTP_PORT = "80";// 或"80"

    public static Boolean sendMail(String subject, String content, List<String> emails) {
        // 配置发送邮件的环境属性
        final Properties props = new Properties();
        // 表示SMTP发送邮件，需要进行身份验证
        props.put("mail.smtp.auth", "true");
        props.put("mail.smtp.host", ALIDM_SMTP_HOST);
        // props.put("mail.smtp.port", ALIDM_SMTP_PORT);
        // 如果使用ssl，则去掉使用25端口的配置，进行如下配置,
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.port", "465");
        props.put("mail.smtp.ssl.enable", "true"); // 开启ssl
        // 发件人的账号
        props.put("mail.user", email_account);
        // 访问SMTP服务时需要提供的密码
        props.put("mail.password", email_password);
        // 构建授权信息，用于进行SMTP进行身份验证
        Authenticator authenticator = new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                // 用户名、密码
                String userName = props.getProperty("mail.user");
                String password = props.getProperty("mail.password");
                return new PasswordAuthentication(userName, password);
            }
        };
        // 使用环境属性和授权信息，创建邮件会话
        Session mailSession = Session.getInstance(props, authenticator);
        // mailSession.setDebug(true);
        // 创建邮件消息
        MimeMessage message = new MimeMessage(mailSession);
        try {
            // 设置发件人
            InternetAddress from = new InternetAddress(email_account);
            message.setFrom(from);
            Address[] a = new Address[1];
            a[0] = new InternetAddress(email_account);
            message.setReplyTo(a);
            // 设置收件人
            if (emails.size() > 1) {
                Address[] address = new InternetAddress[emails.size()];
                for (int i = 0; i < emails.size(); i++) {
                    address[i] = new InternetAddress(emails.get(i));
                }
                message.setRecipients(Message.RecipientType.TO, address);
            } else {
                InternetAddress to = new InternetAddress(emails.get(0));
                message.setRecipient(MimeMessage.RecipientType.TO, to);
            }

            // 设置邮件标题
            message.setSubject(subject);
            // 设置邮件的内容体
            message.setContent(content, "text/html;charset=UTF-8");
            // 发送邮件
            Transport.send(message);
        } catch (MessagingException e) {
            e.printStackTrace();
            logger.error("【发邮件出错】", e);
            String err = e.getMessage();
            // 在这里处理message内容， 格式是固定的
            System.out.println(err);
            return false;
        }
        return true;
    }

    // PS: 某些邮箱服务器为了增加邮箱本身密码的安全性，给 SMTP 客户端设置了独立密码（有的邮箱称为“授权码”）,
    // 对于开启了独立密码的邮箱, 这里的邮箱密码必需使用这个独立密码（授权码）。
    // 发件人邮箱的 SMTP 服务器地址, 必须准确, 不同邮件服务器地址不同, 一般(只是一般, 绝非绝对)格式为: smtp.xxx.com
    // 网易163邮箱的 SMTP 服务器地址为: smtp.163.com

    /**
     * @param subject
     * @param content
     * @param fileName
     * @param is
     * @param emails
     * @return
     * @throws Exception
     */
    public static Boolean sendEmail(String subject, String content, String fileName, InputStream is,
                                    List<String> emails) throws Exception {
        System.getProperties().setProperty("mail.mime.splitlongparameters", "false"); // 解决附件名称过长格式错误的问题

        // 1. 创建参数配置, 用于连接邮件服务器的参数配置
        Properties props = new Properties();
        props.setProperty("mail.transport.protocol", "smtp"); // 使用的协议（JavaMail规范要求）
        props.setProperty("mail.smtp.host", ALIDM_SMTP_HOST); // 发件人的邮箱的 SMTP
        // 服务器地址
        props.setProperty("mail.smtp.auth", "true"); // 需要请求认证
        logger.info("创建参数配置, 用于连接邮件服务器的参数配置完成！》》》》》》》》");
        // PS: 某些邮箱服务器要求 SMTP 连接需要使用 SSL 安全认证 (为了提高安全性, 邮箱支持SSL连接, 也可以自己开启),
        // 如果无法连接邮件服务器, 仔细查看控制台打印的 log, 如果有有类似 “连接失败, 要求 SSL 安全连接” 等错误,
        // 打开下面 /* ... */ 之间的注释代码, 开启 SSL 安全连接。
        // SMTP 服务器的端口 (非 SSL 连接的端口一般默认为 25, 可以不添加, 如果开启了 SSL 连接,
        // 需要改为对应邮箱的 SMTP 服务器的端口, 具体可查看对应邮箱服务的帮助,
        // QQ邮箱的SMTP(SLL)端口为465或587, 其他邮箱自行去查看)

        // 如果使用ssl，则去掉使用25端口的配置，进行如下配置,
        props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
        props.put("mail.smtp.socketFactory.port", "465");
        props.put("mail.smtp.port", "465");
        props.put("mail.smtp.ssl.enable", "true"); // 开启ssl

        // 2. 根据配置创建会话对象, 用于和邮件服务器交互
        Session session = Session.getInstance(props);
        session.setDebug(false); // 设置为debug模式, 可以查看详细的发送 log
        logger.info("根据配置创建session会话对象, 用于和邮件服务器交互完成！》》》》》》》》");
        // 3. 创建一封邮件
        MimeMessage message = createMimeMessage(session, subject, content, fileName, is, emails);
        logger.info("创建一封邮件完成！》》》》》》》》");
        // 4. 根据 Session 获取邮件传输对象
        Transport transport = session.getTransport();

        // 5. 使用 邮箱账号 和 密码 连接邮件服务器, 这里认证的邮箱必须与 message 中的发件人邮箱一致, 否则报错
        //
        // PS_01: 成败的判断关键在此一句, 如果连接服务器失败, 都会在控制台输出相应失败原因的 log,
        // 仔细查看失败原因, 有些邮箱服务器会返回错误码或查看错误类型的链接, 根据给出的错误
        // 类型到对应邮件服务器的帮助网站上查看具体失败原因。
        //
        // PS_02: 连接失败的原因通常为以下几点, 仔细检查代码:
        // (1) 邮箱没有开启 SMTP 服务;
        // (2) 邮箱密码错误, 例如某些邮箱开启了独立密码;
        // (3) 邮箱服务器要求必须要使用 SSL 安全连接;
        // (4) 请求过于频繁或其他原因, 被邮件服务器拒绝服务;
        // (5) 如果以上几点都确定无误, 到邮件服务器网站查找帮助。
        //
        // PS_03: 仔细看log,错误原因都在log已说明。
        transport.connect(email_account, email_password);
        transport.sendMessage(message, message.getAllRecipients());
        transport.close();
        if (is != null) {
            is.close();
        }
        FileUtil.deleteFile(fileName);
        logger.info("发封邮件完成！》》》》》》》》");
        return true;
    }

    /**
     * 创建一封复杂邮件（文本+图片+附件）
     *
     * @param session 和服务器交互的会话
     * @param
     * @return
     * @throws Exception
     */
    private static MimeMessage createMimeMessage(Session session, String subject, String content, String fileName,
                                                 InputStream is, List<String> emails)
            throws Exception {
        MimeMessage message = new MimeMessage(session);

        message.setFrom(new InternetAddress(email_account, "", "UTF-8"));

        // 设置收件人
        if (emails.size() > 1) {
            Address[] address = new InternetAddress[emails.size()];
            for (int i = 0; i < emails.size(); i++) {
                address[i] = new InternetAddress(emails.get(i));
            }
            message.setRecipients(Message.RecipientType.TO, address);
        } else {
            message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(emails.get(0)));
        }

        // Subject: 邮件主题
        message.setSubject(subject, "UTF-8");

        // 创建文本“节点”
        MimeBodyPart text = new MimeBodyPart();
        // 这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片
        text.setContent(content, "text/html;charset=UTF-8");

        // （文本+图片）设置 文本 和 图片 “节点”的关系（将 文本 和 图片 “节点”合成一个混合“节点”）
        MimeMultipart mm_text_image = new MimeMultipart();
        mm_text_image.addBodyPart(text);
        mm_text_image.setSubType("related"); // 关联关系

        // 将 文本+图片 的混合“节点”封装成一个普通“节点”
        // 最终添加到邮件的 Content 是由多个 BodyPart 组成的 Multipart, 所以我们需要的是 BodyPart,
        // 上面的 mm_text_image 并非 BodyPart, 所有要把 mm_text_image 封装成一个 BodyPart
        MimeBodyPart text_image = new MimeBodyPart();
        text_image.setContent(mm_text_image);

        // 创建附件“节点”
        MimeBodyPart attachment = new MimeBodyPart();

        fileName = fileName.substring(fileName.lastIndexOf("/") + 1); // 文件名
        String attachmentName = fileName;

        DataHandler dh2 = new DataHandler(new ByteArrayDataSource(is, "application/png")); // 读取文件
        attachment.setDataHandler(dh2); // 将附件数据添加到“节点”
        attachment.setFileName(MimeUtility.encodeText(attachmentName)); // 设置附件的文件名（需要编码）

        // 设置（文本+图片）和 附件 的关系（合成一个大的混合“节点” / Multipart ）
        MimeMultipart mm = new MimeMultipart();
        mm.addBodyPart(text_image);
        mm.addBodyPart(attachment); // 如果有多个附件，可以创建多个多次添加
        mm.setSubType("mixed"); // 混合关系

        // 设置整个邮件的关系（将最终的混合“节点”作为邮件的内容添加到邮件对象）
        message.setContent(mm);

        message.setSentDate(new Date());

        message.saveChanges();

        return message;
    }


    /**
     * 创建一封复杂邮件（嵌套HTML页面）
     * @param session 和服务器交互的会话
     * @param emailsCC 抄送人邮箱
     * @return
     * @throws Exception
     */
//	public static MimeMessage createMimeMessage(Session session, String subject, List<String> emailsTO
//			, List<String> emailsCC, Integer num, Integer num2, List<StoreOverduePaymentBeanDto> overdueList
//			, String opOverdueUrl, String toName) throws Exception {
//		MimeMessage message = new MimeMessage(session);
//
//		// 设置收件人
//		if (emailsTO.size() > 1) {
//			Address[] address = new InternetAddress[emailsTO.size()];
//			for (int i = 0; i < emailsTO.size(); i++) {
//				address[i] = new InternetAddress(emailsTO.get(i));
//			}
//			message.setRecipients(Message.RecipientType.TO, address);
//		} else {
//			message.setRecipient(MimeMessage.RecipientType.TO, new InternetAddress(emailsTO.get(0)));
//		}
//		// 设置抄送人
//		if (emailsCC.size() > 1) {
//			Address[] address = new InternetAddress[emailsCC.size()];
//			for (int i = 0; i < emailsCC.size(); i++) {
//				address[i] = new InternetAddress(emailsCC.get(i));
//			}
//			message.setRecipients(Message.RecipientType.CC, address);
//		} else {
//			message.setRecipient(MimeMessage.RecipientType.CC, new InternetAddress(emailsCC.get(0)));
//		}
//		// 设置发件人
//		message.setFrom(new InternetAddress(email_account, "", "UTF-8"));
//		// 邮件主题
//		message.setSubject(subject, "UTF-8");
//
//		// 创建文本“节点”
//		MimeBodyPart text = new MimeBodyPart();
//		//  这里添加图片的方式是将整个图片包含到邮件内容中, 实际上也可以以 http 链接的形式添加网络图片
//		// 拼接数据
//		String result = MailUtil.readFile();
//		result = StringUtils.replace(result, "{overdue_user}", toName);
//		result = StringUtils.replace(result, "{overdue_num}", num+"");
//		result = StringUtils.replace(result, "{overdue_num2}", num2+"");
//		result = StringUtils.replace(result, "{overdue_op}", opOverdueUrl);
//
//		StringBuilder data = new StringBuilder();
//		if (overdueList!=null && !overdueList.isEmpty()){
//			for (int i=0; i<overdueList.size(); i++){
//				String tmp = "<div class='tr'> <div class='td'>"+overdueList.get(i).getStoreName()
//						+"</div> <div class='td'>"+overdueList.get(i).getNum()+"笔</div></div>";
//				data.append(tmp);
//			}
//			result = StringUtils.replace(result, "{overdue_date}", data.toString());
//		}else {
//			result = StringUtils.replace(result, "{overdue_date}", "");
//		}
//		text.setContent(result, "text/html;charset=UTF-8");
//
//		MimeMultipart mm_text_image = new MimeMultipart();
//		mm_text_image.addBodyPart(text);
//		mm_text_image.setSubType("related");    // 关联关系
//
//		MimeBodyPart text_image = new MimeBodyPart();
//		text_image.setContent(mm_text_image);
//
//		MimeMultipart mm = new MimeMultipart();
//		mm.addBodyPart(text_image);
//		mm.setSubType("mixed");         // 混合关系
//
//		message.setContent(mm);
//		message.setSentDate(new Date());
//		message.saveChanges();
//
//		return message;
//	}

    /**
     * 将html文件读成String代码
     *
     * @return
     * @throws Exception
     */
    public static String readFile() throws Exception {
        ClassPathResource resource = new ClassPathResource("index.html");
        InputStream inputStream = resource.getInputStream();
        BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        StringBuilder sb = new StringBuilder();
        try {
            String line;
            while ((line = in.readLine()) != null) {
                sb.append(line);
                sb.append("\n");
            }
            System.out.println(sb);
        } finally {
            in.close();
        }
        return sb.toString();
    }

    /**
     * 发送嵌套html的逾期还款订单信息
     * @param subject 主题
     * @param emailsTO 收件人
     * @param emailsCC 抄送人
     * @param num 总条数
     * @param overdueList 逾期信息
     * @param opOverdueUrl OP地址
     * @return
     * @throws Exception
     */
//	public static Boolean sendEmailOverdue(String subject, List<String> emailsTO, List<String> emailsCC, Integer num
//			, Integer num2, List<StoreOverduePaymentBeanDto> overdueList, String opOverdueUrl, String toName)
//			throws Exception {
//		System.getProperties().setProperty("mail.mime.splitlongparameters", "false"); // 解决附件名称过长格式错误的问题
//		Properties props = new Properties();
//		props.setProperty("mail.transport.protocol", "smtp"); // 使用的协议（JavaMail规范要求）
//		props.setProperty("mail.smtp.host", ALIDM_SMTP_HOST); // 发件人的邮箱的 SMTP
//		// 服务器地址
//		props.setProperty("mail.smtp.auth", "true"); // 需要请求认证
//		logger.info("创建参数配置, 用于连接邮件服务器的参数配置完成！》》》》》》》》");
//		// PS: 某些邮箱服务器要求 SMTP 连接需要使用 SSL 安全认证 (为了提高安全性, 邮箱支持SSL连接, 也可以自己开启),
//		// 如果无法连接邮件服务器, 仔细查看控制台打印的 log, 如果有有类似 “连接失败, 要求 SSL 安全连接” 等错误,
//		// 打开下面 /* ... */ 之间的注释代码, 开启 SSL 安全连接。
//		// SMTP 服务器的端口 (非 SSL 连接的端口一般默认为 25, 可以不添加, 如果开启了 SSL 连接,
//		// 需要改为对应邮箱的 SMTP 服务器的端口, 具体可查看对应邮箱服务的帮助,
//		// QQ邮箱的SMTP(SLL)端口为465或587, 其他邮箱自行去查看)
//
//		// 如果使用ssl，则去掉使用25端口的配置，进行如下配置,
//		props.put("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
//		props.put("mail.smtp.socketFactory.port", "465");
//		props.put("mail.smtp.port", "465");
//		props.put("mail.smtp.ssl.enable", "true"); // 开启ssl
//
//		// 2. 根据配置创建会话对象, 用于和邮件服务器交互
//		Session session = Session.getInstance(props);
//		session.setDebug(false); // 设置为debug模式, 可以查看详细的发送 log
//		logger.info("根据配置创建session会话对象, 用于和邮件服务器交互完成！》》》》》》》》");
//		// 3. 创建一封邮件
//		MimeMessage message = createMimeMessage(session, subject, emailsTO, emailsCC, num, num2, overdueList
//				, opOverdueUrl, toName);
//		logger.info("创建一封邮件完成！》》》》》》》》");
//		// 4. 根据 Session 获取邮件传输对象
//		Transport transport = session.getTransport();
//
//		// 5. 使用 邮箱账号 和 密码 连接邮件服务器, 这里认证的邮箱必须与 message 中的发件人邮箱一致, 否则报错
//		//
//		// PS_01: 成败的判断关键在此一句, 如果连接服务器失败, 都会在控制台输出相应失败原因的 log,
//		// 仔细查看失败原因, 有些邮箱服务器会返回错误码或查看错误类型的链接, 根据给出的错误
//		// 类型到对应邮件服务器的帮助网站上查看具体失败原因。
//		//
//		// PS_02: 连接失败的原因通常为以下几点, 仔细检查代码:
//		// (1) 邮箱没有开启 SMTP 服务;
//		// (2) 邮箱密码错误, 例如某些邮箱开启了独立密码;
//		// (3) 邮箱服务器要求必须要使用 SSL 安全连接;
//		// (4) 请求过于频繁或其他原因, 被邮件服务器拒绝服务;
//		// (5) 如果以上几点都确定无误, 到邮件服务器网站查找帮助。
//		//
//		// PS_03: 仔细看log,错误原因都在log已说明。
//		transport.connect(email_account, email_password);
//		transport.sendMessage(message, message.getAllRecipients());
//		transport.close();
//		logger.info("发封邮件完成！》》》》》》》》");
//		return true;
//	}
    public static void main(String[] args) {

    }

}
